// Copyright (c) 2018, Yubico AB
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.yubico.webauthn

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.node.JsonNodeFactory
import com.fasterxml.jackson.databind.node.ObjectNode
import com.yubico.internal.util.BinaryUtil
import com.yubico.internal.util.CertificateParser
import com.yubico.internal.util.JacksonCodecs
import com.yubico.internal.util.scala.JavaConverters._
import com.yubico.webauthn.TestAuthenticator.AttestationCert
import com.yubico.webauthn.TestAuthenticator.AttestationMaker
import com.yubico.webauthn.TestAuthenticator.AttestationSigner
import com.yubico.webauthn.data.AttestationObject
import com.yubico.webauthn.data.AuthenticatorAssertionResponse
import com.yubico.webauthn.data.AuthenticatorAttestationResponse
import com.yubico.webauthn.data.AuthenticatorSelectionCriteria
import com.yubico.webauthn.data.ByteArray
import com.yubico.webauthn.data.COSEAlgorithmIdentifier
import com.yubico.webauthn.data.ClientAssertionExtensionOutputs
import com.yubico.webauthn.data.ClientRegistrationExtensionOutputs
import com.yubico.webauthn.data.CollectedClientData
import com.yubico.webauthn.data.PublicKeyCredential
import com.yubico.webauthn.data.PublicKeyCredentialCreationOptions
import com.yubico.webauthn.data.PublicKeyCredentialParameters
import com.yubico.webauthn.data.RegistrationExtensionInputs
import com.yubico.webauthn.data.RelyingPartyIdentity
import com.yubico.webauthn.data.UserIdentity
import org.bouncycastle.asn1.x500.X500Name

import java.nio.charset.StandardCharsets
import java.security.KeyPair
import java.security.cert.X509Certificate
import scala.jdk.CollectionConverters._
import scala.util.Failure
import scala.util.Success
import scala.util.Try

object RegistrationTestDataGenerator extends App {
  regenerateTestData()

  def printTestDataCode(
      testData: RegistrationTestData
  ): Unit = {
    println(
      s"""attestationObject = ByteArray.fromHex("${testData.attestationObject.getHex}"),
               |clientDataJson = \"\"\"${testData.clientDataJson}\"\"\",
               |privateKey = Some(ByteArray.fromHex("${testData.privateKey.get.getHex}")),
               """.stripMargin
    )

    testData.assertion foreach { assertion =>
      println(s"""|assertion = Some(AssertionTestData(
                  |  request = JacksonCodecs.json().readValue(\"\"\"${JacksonCodecs
        .json()
        .writeValueAsString(
          assertion.request
        )}\"\"\", classOf[AssertionRequest]),
                  |  response = PublicKeyCredential.parseAssertionResponseJson(\"\"\"${JacksonCodecs
        .json()
        .writeValueAsString(assertion.response)}\"\"\")
                  |)),
                  """.stripMargin)
    }
  }

  def regenerateTestData(): Unit = {
    val td = RegistrationTestData
    for {
      (testData, i) <- List(
        td.AndroidSafetynet.BasicAttestation,
        td.AndroidSafetynet.WrongHostname,
        td.AndroidSafetynet.FalseCtsProfileMatch,
        td.FidoU2f.BasicAttestation,
        td.FidoU2f.SelfAttestation,
        td.NoneAttestation.Default,
        td.Packed.BasicAttestation,
        td.Packed.BasicAttestationEdDsa,
        td.Packed.BasicAttestationRsa,
        td.Packed.BasicAttestationRs1,
        td.Packed.BasicAttestationWithoutAaguidExtension,
        td.Packed.BasicAttestationWithWrongAaguidExtension,
        td.Packed.SelfAttestation,
        td.Packed.SelfAttestationRs1,
      ).zipWithIndex
    } {
      testData.regenerateFull() match {
        case Success(newTestData) =>
          println(i)
          printTestDataCode(newTestData)
        case Failure(e) =>
          println("Failed to regenerate")
          e.printStackTrace()
      }
    }
  }
}

object RegistrationTestData {
  private def jsonFactory: JsonNodeFactory = JsonNodeFactory.instance

  def defaultSettingsValidExamples =
    List(
      AndroidSafetynet.RealExample,
      AndroidSafetynet.BasicAttestation,
      FidoU2f.BasicAttestation,
      FidoU2f.SelfAttestation,
      NoneAttestation.Default,
      Packed.BasicAttestation,
      Packed.BasicAttestationEdDsa,
      Packed.BasicAttestationRsa,
      Packed.BasicAttestationRsaReal,
      Packed.SelfAttestation,
    )

  object AndroidKey {
    val BasicAttestation: RegistrationTestData =
      Packed.SelfAttestation.setAttestationStatementFormat("android-key")
  }
  object AndroidSafetynet {
    val RealExample: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject =
        ByteArray.fromBase64Url("o2NmbXRxYW5kcm9pZC1zYWZldHluZXRnYXR0U3RtdKJjdmVyaDE0Nzk5MDIxaHJlc3BvbnNlWRS9ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbmcxWXlJNld5Sk5TVWxHYTJwRFEwSkljV2RCZDBsQ1FXZEpVVkpZY205T01GcFBaRkpyUWtGQlFVRkJRVkIxYm5wQlRrSm5hM0ZvYTJsSE9YY3dRa0ZSYzBaQlJFSkRUVkZ6ZDBOUldVUldVVkZIUlhkS1ZsVjZSV1ZOUW5kSFFURlZSVU5vVFZaU01qbDJXako0YkVsR1VubGtXRTR3U1VaT2JHTnVXbkJaTWxaNlRWSk5kMFZSV1VSV1VWRkVSWGR3U0ZaR1RXZFJNRVZuVFZVNGVFMUNORmhFVkVVMFRWUkJlRTFFUVROTlZHc3dUbFp2V0VSVVJUVk5WRUYzVDFSQk0wMVVhekJPVm05M1lrUkZURTFCYTBkQk1WVkZRbWhOUTFaV1RYaEZla0ZTUW1kT1ZrSkJaMVJEYTA1b1lrZHNiV0l6U25WaFYwVjRSbXBCVlVKblRsWkNRV05VUkZVeGRtUlhOVEJaVjJ4MVNVWmFjRnBZWTNoRmVrRlNRbWRPVmtKQmIxUkRhMlIyWWpKa2MxcFRRazFVUlUxNFIzcEJXa0puVGxaQ1FVMVVSVzFHTUdSSFZucGtRelZvWW0xU2VXSXliR3RNYlU1MllsUkRRMEZUU1hkRVVWbEtTMjlhU1doMlkwNUJVVVZDUWxGQlJHZG5SVkJCUkVORFFWRnZRMmRuUlVKQlRtcFlhM293WlVzeFUwVTBiU3N2UnpWM1QyOHJXRWRUUlVOeWNXUnVPRGh6UTNCU04yWnpNVFJtU3pCU2FETmFRMWxhVEVaSWNVSnJOa0Z0V2xaM01rczVSa2N3VHpseVVsQmxVVVJKVmxKNVJUTXdVWFZ1VXpsMVowaEROR1ZuT1c5MmRrOXRLMUZrV2pKd09UTllhSHAxYmxGRmFGVlhXRU40UVVSSlJVZEtTek5UTW1GQlpucGxPVGxRVEZNeU9XaE1ZMUYxV1ZoSVJHRkROMDlhY1U1dWIzTnBUMGRwWm5NNGRqRnFhVFpJTDNob2JIUkRXbVV5YkVvck4wZDFkSHBsZUV0d2VIWndSUzkwV2xObVlsazVNRFZ4VTJ4Q2FEbG1jR293TVRWamFtNVJSbXRWYzBGVmQyMUxWa0ZWZFdWVmVqUjBTMk5HU3pSd1pYWk9UR0Y0UlVGc0swOXJhV3hOZEVsWlJHRmpSRFZ1Wld3MGVFcHBlWE0wTVROb1lXZHhWekJYYUdnMVJsQXpPV2hIYXpsRkwwSjNVVlJxWVhwVGVFZGtkbGd3YlRaNFJsbG9hQzh5VmsxNVdtcFVORXQ2VUVwRlEwRjNSVUZCWVU5RFFXeG5kMmRuU2xWTlFUUkhRVEZWWkVSM1JVSXZkMUZGUVhkSlJtOUVRVlJDWjA1V1NGTlZSVVJFUVV0Q1oyZHlRbWRGUmtKUlkwUkJWRUZOUW1kT1ZraFNUVUpCWmpoRlFXcEJRVTFDTUVkQk1WVmtSR2RSVjBKQ1VYRkNVWGRIVjI5S1FtRXhiMVJMY1hWd2J6UlhObmhVTm1veVJFRm1RbWRPVmtoVFRVVkhSRUZYWjBKVFdUQm1hSFZGVDNaUWJTdDRaMjU0YVZGSE5rUnlabEZ1T1V0NlFtdENaMmR5UW1kRlJrSlJZMEpCVVZKWlRVWlpkMHAzV1VsTGQxbENRbEZWU0UxQlIwZEhNbWd3WkVoQk5reDVPWFpaTTA1M1RHNUNjbUZUTlc1aU1qbHVUREprTUdONlJuWk5WRUZ5UW1kbmNrSm5SVVpDVVdOM1FXOVpabUZJVWpCalJHOTJURE5DY21GVE5XNWlNamx1VERKa2VtTnFTWFpTTVZKVVRWVTRlRXh0VG5sa1JFRmtRbWRPVmtoU1JVVkdha0ZWWjJoS2FHUklVbXhqTTFGMVdWYzFhMk50T1hCYVF6VnFZakl3ZDBsUldVUldVakJuUWtKdmQwZEVRVWxDWjFwdVoxRjNRa0ZuU1hkRVFWbExTM2RaUWtKQlNGZGxVVWxHUVhwQmRrSm5UbFpJVWpoRlMwUkJiVTFEVTJkSmNVRm5hR2cxYjJSSVVuZFBhVGgyV1ROS2MweHVRbkpoVXpWdVlqSTVia3d3WkZWVmVrWlFUVk0xYW1OdGQzZG5aMFZGUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpKU0RGQ1NVaDVRVkJCUVdSM1EydDFVVzFSZEVKb1dVWkpaVGRGTmt4TldqTkJTMUJFVjFsQ1VHdGlNemRxYW1RNE1FOTVRVE5qUlVGQlFVRlhXbVJFTTFCTVFVRkJSVUYzUWtsTlJWbERTVkZEVTFwRFYyVk1Tblp6YVZaWE5rTm5LMmRxTHpsM1dWUktVbnAxTkVocGNXVTBaVmswWXk5dGVYcHFaMGxvUVV4VFlta3ZWR2g2WTNweGRHbHFNMlJyTTNaaVRHTkpWek5NYkRKQ01HODNOVWRSWkdoTmFXZGlRbWRCU0ZWQlZtaFJSMjFwTDFoM2RYcFVPV1ZIT1ZKTVNTdDRNRm95ZFdKNVdrVldla0UzTlZOWlZtUmhTakJPTUVGQlFVWnRXRkU1ZWpWQlFVRkNRVTFCVW1wQ1JVRnBRbU5EZDBFNWFqZE9WRWRZVURJM09IbzBhSEl2ZFVOSWFVRkdUSGx2UTNFeVN6QXJlVXhTZDBwVlltZEpaMlk0WjBocWRuQjNNbTFDTVVWVGFuRXlUMll6UVRCQlJVRjNRMnR1UTJGRlMwWlZlVm8zWmk5UmRFbDNSRkZaU2t0dldrbG9kbU5PUVZGRlRFSlJRVVJuWjBWQ1FVazVibFJtVWt0SlYyZDBiRmRzTTNkQ1REVTFSVlJXTm10aGVuTndhRmN4ZVVGak5VUjFiVFpZVHpReGExcDZkMG8yTVhkS2JXUlNVbFF2VlhORFNYa3hTMFYwTW1Nd1JXcG5iRzVLUTBZeVpXRjNZMFZYYkV4UldUSllVRXg1Um1wclYxRk9ZbE5vUWpGcE5GY3lUbEpIZWxCb2RETnRNV0kwT1doaWMzUjFXRTAyZEZnMVEzbEZTRzVVYURoQ2IyMDBMMWRzUm1sb2VtaG5iamd4Ukd4a2IyZDZMMHN5VlhkTk5sTTJRMEl2VTBWNGEybFdabllyZW1KS01ISnFkbWM1TkVGc1pHcFZabFYzYTBrNVZrNU5ha1ZRTldVNGVXUkNNMjlNYkRabmJIQkRaVVkxWkdkbVUxZzBWVGw0TXpWdmFpOUpTV1F6VlVVdlpGQndZaTl4WjBkMmMydG1aR1Y2ZEcxVmRHVXZTMU50Y21sM1kyZFZWMWRsV0daVVlra3plbk5wYTNkYVltdHdiVkpaUzIxcVVHMW9kalJ5YkdsNlIwTkhkRGhRYmpod2NUaE5Na3RFWmk5UU0ydFdiM1F6WlRFNFVUMGlMQ0pOU1VsRlUycERRMEY2UzJkQmQwbENRV2RKVGtGbFR6QnRjVWRPYVhGdFFrcFhiRkYxUkVGT1FtZHJjV2hyYVVjNWR6QkNRVkZ6UmtGRVFrMU5VMEYzU0dkWlJGWlJVVXhGZUdSSVlrYzVhVmxYZUZSaFYyUjFTVVpLZG1JelVXZFJNRVZuVEZOQ1UwMXFSVlJOUWtWSFFURlZSVU5vVFV0U01uaDJXVzFHYzFVeWJHNWlha1ZVVFVKRlIwRXhWVVZCZUUxTFVqSjRkbGx0Um5OVk1teHVZbXBCWlVaM01IaE9la0V5VFZSVmQwMUVRWGRPUkVwaFJuY3dlVTFVUlhsTlZGVjNUVVJCZDA1RVNtRk5SVWw0UTNwQlNrSm5UbFpDUVZsVVFXeFdWRTFTTkhkSVFWbEVWbEZSUzBWNFZraGlNamx1WWtkVloxWklTakZqTTFGblZUSldlV1J0YkdwYVdFMTRSWHBCVWtKblRsWkNRVTFVUTJ0a1ZWVjVRa1JSVTBGNFZIcEZkMmRuUldsTlFUQkhRMU54UjFOSllqTkVVVVZDUVZGVlFVRTBTVUpFZDBGM1oyZEZTMEZ2U1VKQlVVUlJSMDA1UmpGSmRrNHdOWHByVVU4NUszUk9NWEJKVW5aS2VucDVUMVJJVnpWRWVrVmFhRVF5WlZCRGJuWlZRVEJSYXpJNFJtZEpRMlpMY1VNNVJXdHpRelJVTW1aWFFsbHJMMnBEWmtNelVqTldXazFrVXk5a1RqUmFTME5GVUZwU2NrRjZSSE5wUzFWRWVsSnliVUpDU2pWM2RXUm5lbTVrU1UxWlkweGxMMUpIUjBac05YbFBSRWxMWjJwRmRpOVRTa2d2VlV3clpFVmhiSFJPTVRGQ2JYTkxLMlZSYlUxR0t5dEJZM2hIVG1oeU5UbHhUUzg1YVd3M01Va3laRTQ0UmtkbVkyUmtkM1ZoWldvMFlsaG9jREJNWTFGQ1ltcDRUV05KTjBwUU1HRk5NMVEwU1N0RWMyRjRiVXRHYzJKcWVtRlVUa001ZFhwd1JteG5UMGxuTjNKU01qVjRiM2x1VlhoMk9IWk9iV3R4TjNwa1VFZElXR3Q0VjFrM2IwYzVhaXRLYTFKNVFrRkNhemRZY2twbWIzVmpRbHBGY1VaS1NsTlFhemRZUVRCTVMxY3dXVE42Tlc5Nk1rUXdZekYwU2t0M1NFRm5UVUpCUVVkcVoyZEZlazFKU1VKTWVrRlBRbWRPVmtoUk9FSkJaamhGUWtGTlEwRlpXWGRJVVZsRVZsSXdiRUpDV1hkR1FWbEpTM2RaUWtKUlZVaEJkMFZIUTBOelIwRlJWVVpDZDAxRFRVSkpSMEV4VldSRmQwVkNMM2RSU1UxQldVSkJaamhEUVZGQmQwaFJXVVJXVWpCUFFrSlpSVVpLYWxJclJ6UlJOamdyWWpkSFEyWkhTa0ZpYjA5ME9VTm1NSEpOUWpoSFFURlZaRWwzVVZsTlFtRkJSa3AyYVVJeFpHNUlRamRCWVdkaVpWZGlVMkZNWkM5alIxbFpkVTFFVlVkRFEzTkhRVkZWUmtKM1JVSkNRMnQzU25wQmJFSm5aM0pDWjBWR1FsRmpkMEZaV1ZwaFNGSXdZMFJ2ZGt3eU9XcGpNMEYxWTBkMGNFeHRaSFppTW1OMldqTk9lVTFxUVhsQ1owNVdTRkk0UlV0NlFYQk5RMlZuU21GQmFtaHBSbTlrU0ZKM1QyazRkbGt6U25OTWJrSnlZVk0xYm1JeU9XNU1NbVI2WTJwSmRsb3pUbmxOYVRWcVkyMTNkMUIzV1VSV1VqQm5Ra1JuZDA1cVFUQkNaMXB1WjFGM1FrRm5TWGRMYWtGdlFtZG5ja0puUlVaQ1VXTkRRVkpaWTJGSVVqQmpTRTAyVEhrNWQyRXlhM1ZhTWpsMlduazVlVnBZUW5aak1td3dZak5LTlV4NlFVNUNaMnR4YUd0cFJ6bDNNRUpCVVhOR1FVRlBRMEZSUlVGSGIwRXJUbTV1TnpoNU5uQlNhbVE1V0d4UlYwNWhOMGhVWjJsYUwzSXpVazVIYTIxVmJWbElVRkZ4TmxOamRHazVVRVZoYW5aM1VsUXlhVmRVU0ZGeU1ESm1aWE54VDNGQ1dUSkZWRlYzWjFwUksyeHNkRzlPUm5ab2MwODVkSFpDUTA5SllYcHdjM2RYUXpsaFNqbDRhblUwZEZkRVVVZzRUbFpWTmxsYVdpOVlkR1ZFVTBkVk9WbDZTbkZRYWxrNGNUTk5SSGh5ZW0xeFpYQkNRMlkxYnpodGR5OTNTalJoTWtjMmVIcFZjalpHWWpaVU9FMWpSRTh5TWxCTVVrdzJkVE5OTkZSNmN6TkJNazB4YWpaaWVXdEtXV2s0ZDFkSlVtUkJka3RNVjFwMUwyRjRRbFppZWxsdGNXMTNhMjAxZWt4VFJGYzFia2xCU21KRlRFTlJRMXAzVFVnMU5uUXlSSFp4YjJaNGN6WkNRbU5EUmtsYVZWTndlSFUyZURaMFpEQldOMU4yU2tORGIzTnBjbE50U1dGMGFpODVaRk5UVmtSUmFXSmxkRGh4THpkVlN6UjJORnBWVGpnd1lYUnVXbm94ZVdjOVBTSmRmUS5leUp1YjI1alpTSTZJa3RDT1hwd01tTlJXRlpLVUdkbWIzWkpNREp6UVRkbk1rMVFMMWh2UzFaQlpHZzRNMjA1U2podGFWRTlJaXdpZEdsdFpYTjBZVzF3VFhNaU9qRTFORGMxTmpFNE1qSXhNakVzSW1Gd2ExQmhZMnRoWjJWT1lXMWxJam9pWTI5dExtZHZiMmRzWlM1aGJtUnliMmxrTG1kdGN5SXNJbUZ3YTBScFoyVnpkRk5vWVRJMU5pSTZJa3B4UzBNNVoweGlWMHRNZFM4eU1ubElLMDl0VUdSc1RuQXljemhOVlZGa1VUWXhXVUp5ZGpoQ2QyODlJaXdpWTNSelVISnZabWxzWlUxaGRHTm9JanAwY25WbExDSmhjR3REWlhKMGFXWnBZMkYwWlVScFoyVnpkRk5vWVRJMU5pSTZXeUk0VURGelZ6QkZVRXBqYzJ4M04xVjZVbk5wV0V3Mk5IY3JUelV3UldRclVrSkpRM1JoZVRGbk1qUk5QU0pkTENKaVlYTnBZMGx1ZEdWbmNtbDBlU0k2ZEhKMVpYMC5TVEp1N0xnR29VWHQzZmtveXZMZEIyd0VHZ3VHOUc0QnpEUWxFYkQ3a0dSVWdmZDd2ZHUxUGwtbWNlUUd6cnJWUEY5eHRERXFHWnR6YkpILWN1amVVN0RCbTF4eDRzNlBIenZra0xibjg0b1ROUFJNcmhFalpER0tFUHdVZzVXb0M0UUlPSERMN2xpbUN4alhxYVl5eTh0Tk4ybW1yWlBPV3oxRVJGOG1XSG1tU0VrSWNJeVpyTDhuVS1jMkhVM2pyYkF3SDFoWFoxZU1yMG9kUTllbWM2TU8tWUFhSjZ6X2g1a29MSnhGVkxnZTh3dmp6UkE3R0hZdXlzQ3FPTXdCb3FnbVBlVzUxODBLV0VtTXdJUVljd1VXanZDbTRILUlWWUl6RElGcHdMSUFaaFQxd1NHbUoyeDBaQ3lpMlF4SmhRR0RjR1JuZjZyTlllc3FnSXpqV0FoYXV0aERhdGFYxcRs74KtG1Rkd1kdAIsIdZ7D5tLstPOUdL_qaWmSXQO3RQAAAAC5P9lh8uZGL7EiggAiR954AEEBEAglXhhzprEVlCnJSjQ0f59qby7VJKFLROYDyglb0hOGk9VmPeojeh8mwnsf3exgIBoVovCmIaGggiF3YPIV8KUBAgMmIAEhWCDbwAl__SPL0bDsj9WldwIqhh0thFFVRWt0HHm8MT5AVyJYIL1z6R8jvPutwAinX77M3ahwoNxFWPvR15vuhv1af8c6"),
      clientDataJson = """{"type":"webauthn.create","challenge":"jQsu5pUma1KIlCaAUfptSrCZv7a8Qpcxs-N52OuO5ms","origin":"https:\/\/demo.yubico.com","androidPackageName":"com.android.chrome"}""",
      rpId =
        RelyingPartyIdentity.builder().id("demo.yubico.com").name("").build(),
    )

    val BasicAttestation: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject = new ByteArray(
        BinaryUtil.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f0020d787c0d88c8b258e0e147af3f4442103fc7d41718ea92dd2b1be925c6a06113aa52258200b159bf750abbfa9bf8d6a4a806eff06533e9ac9f3576113f57ce6919306a51b03260102215820b9e1f17d71fc5cfbc2e19528b2fa6c9dd9e9a8bd35e692f5e12d71233e91950f200163666d7471616e64726f69642d7361666574796e65746761747453746d74bf6376657268313437393930323168726573706f6e73655907e665794a68624763694f694a53557a49314e694973496e67315979493657794a4e53556c4463565244513046724b32644264306c435157644a51304a55613364445a316c4a53323961535870714d45564264306c335957704662553144555564424d565646515864335a466459566d6c685630353253555a6b62466c72526a466b5232683153556857645746595557646b52315a365a45684e5a31457752586845656b464f516d644f566b4a42623031436247777857573173616d4a3652576c4e513046485154465652554e33643170525746597759556457645752486247705a57464a3259326c43516d5249556d786a4d314a6f5a456473646d4a715255784e515774485154465652554a6f54554e564d4656335347686a546b31555a336450564545795456526a4d4531715158645861474e4f5456526e6430395551544a4e56474d775457704264316471516d5a4e556e4e335231465a52465a5255555245516b706f5a45685362474d7a5558565a567a567259323035634670444e5770694d6a423452487042546b4a6e546c5a435157394e516d78734d566c7462477069656b567054554e42523045785655564464336461555668574d474648566e566b5232787157566853646d4e70516b4a6b53464a73597a4e536147524862485a69616b564d54554672523045785655564361453144565442566432646e52576c4e5154424851314e7852314e4a596a4e4555555643515646565155453053554a45643046335a3264465330467653554a425555524f6332307761544248624535514d575a4455474e4757444e3361316444533370315a466f3051324a5051304a544d6d394b4c7a4a335a6e5a7152555a324f456c4f5630703364325a73554539794b3063784e4552744f466734517a4d7256574e5251565a5763305249625535435a32314b513346475257307654473936633278685a5574335333465052326c3461484e464f53744e53477830616c7079634564614f467069596b527a4f554e705132357a646e6b7754564a4b645464495a4456784e585a7357553947596a4d315545563055585977516b5972557a426b4c3146685344647857476b30646a645a616b6f7a4d485672515752544d306f795747593262544e786153395563537455656c52716245637a53565277545539426556597653304a6b64574934613170774f456f775556497a556a6868614374615a554a7064564630513146335155746b636d314e63456c43555870496455356f613231614c324e736554597956554a31533264714c33646e4d55773156554533527a5a4f645734785a4642326157354d56557868526b6f3251334633513231576248426a53314635636b4a59596d70476445527962475a5256335a4f536c526c5633647a564756706345466e54554a4251556471536c5242616b31445255644465584e4851564652516d643156574e4255555646516b4a4a5255564251554a425a303146516c465a53454e42613074446433644f5247633464304e6e57556c4c6231704a656d6f77525546335355525451554633556c464a5a314e74555456504b7a6c3152576c784d544e70546d6b78566e5a4a645538335430357564546c46516b597a534549794f45687562445661554774445356464563474e68626d3958526b4a784d3074684d7a6c71536e68554e32784457473153616b4e6c54307868567a4a715a6d39715547316a63575a435a7a3039496c31392e65794a68634778445a584a3061575a70593246305a5552705a32567a64464e6f595449314e69493657794a4d5132457759544a714c3368764c7a56744d46553453465243516b3543546b4e4d57454a725a7a63725a79745a63475670523070744e54593050534a644c434a756232356a5a534936496c427165585a6b524539304e554a365a56523561474643646b307a554552705a303158636b6732515652736256464c636c6730566d68314e47733949697769595842725547466a6132466e5a553568625755694f694a6a623230756558566961574e764c6e646c596d4631644768754c6e526c633351694c434a6959584e7059306c756447566e636d6c306553493664484a315a53776964476c745a584e305957317754584d694f6a45314e546b314e6a6b794d7a67314f446773496d4677613052705a32567a64464e6f595449314e694936496b7844595442684d6d6f76654738764e5730775654684956454a43546b4a4f51307859516d746e4e79746e4b316c775a576c48536d30314e6a5139496977695933527a55484a765a6d6c735a55316864474e6f496a7030636e566c66512e76546e4f4f6151514b6e7959356747394d58636c63455237513145347275705a76415f6d77494a4e47745f2d5039436e6d64736366597a7a512d67714b3668537467714c326f6453485f6b6d473441464a4d367a304843712d324d41756262515f38435346507855615f6a5674397334552d7446415a564b64424b796e495f4b3863456b66683364684a664138774c70363268485f6f6b5a63744c6b5f437549787446646f4b587854793675706f4a4e496a4342614a4a314855304b4c424c78704e4543494346363876375368413855466e6e6863726a47456575794d6d634e5f6179535570306a3858536d5651496d7a754c714c4763476c545f647143486b764a673773303850616c53534131726e30634f505a526b41656c37706e65627746623854497373444852475a696639493255787530474774644b31364164797059555242633278642d4769302d30566c616631587577ffff")
      ),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(attestationMaker =
          AttestationMaker.androidSafetynet(
            AttestationSigner.ca(
              alg = COSEAlgorithmIdentifier.RS256,
              certSubject = new X500Name(
                "CN=attest.android.com, O=Yubico, OU=Authenticator Attestation, C=SE"
              ),
            )
          )
        )
    }

    val WrongHostname: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject = new ByteArray(
        BinaryUtil.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f0020bdbf5179112add51874c0824f0d860083d1ee7cb7f44c25ffa26c39271c3ed0aa5225820c35b4c850d7c13334432f7f17a5f1f9a5b1c85bff9b407dc0c962f0eb95eb9d10326010221582041d565e8ca57023f4510f150481d551f84f2dd09894fbc20d1c4707896943638200163666d7471616e64726f69642d7361666574796e65746761747453746d74bf6376657268313437393930323168726573706f6e73655907f165794a68624763694f694a53557a49314e694973496e67315979493657794a4e53556c4463315244513046735a57644264306c435157644a51304a55613364445a316c4a53323961535870714d45564264306c335957704662553144555564424d565646515864335a466459566d6c685630353253555a6b62466c72526a466b5232683153556857645746595557646b52315a365a45684e5a31457752586845656b464f516d644f566b4a42623031436247777857573173616d4a3652576c4e513046485154465652554e33643170525746597759556457645752486247705a57464a3259326c43516d5249556d786a4d314a6f5a456473646d4a715255784e515774485154465652554a6f54554e564d4656335347686a546b31555a336450564545795456526a4d4531715158645861474e4f5456526e6430395551544a4e56474d775457704264316471516d354e553031335356465a52465a5255555245516e42615a46644b63466b794f4764574d6c5a70555668574d4746484e47646b567a56775a454e434d467059546a426a656b56515455457752304578565556445a3364485631685761574658546e5a4e55306c335355465a52465a5255557845516d78435a466853623170584e5442685630356f5a45633565556c46526a426b52315a365a4564474d4746584f58564e55584e335131465a52465a525555644664307055556c5244513046545358644555566c4b53323961535768325930354255555643516c46425247646e5256424252454e44515646765132646e52554a4254573432535539336255786d5356427253546c5256315236546e6c5a4e304d3464444e6956444a5254484179654374324b3342325a6c70424d47686b5a31457852586875656d78574e57314f4e334a744d4735354b3046695a334646546d397265545533646a45764f57644359334d314c7a464e4c315a36555464735743746c4e325275516a4233516c42755355524b5a4374304d3064345a6d597659544645596b4977555535364d567033516a4d325545744f4e5856594e3274364b314d35516b5668616b644f4e47786a5a466c425232644654454a33513168745a55465a62316c47567974475a4763345a473034626d6f76575778314e3168426248464d4c7a423661577053576b6c535530704c4e46705157454e6f626a42314e3246464d553578567a52696332566a536b6c70656e5a34534868546547567257544134656b4673656c4579636a5235626e70754e3235334f476f30566a6c3357575254526d347a5630396d616c5654565578326344453061546c324f4549324e6d677264565a6f4e4578504d3231365a586c5652445a444e587035516e5a5a5757706a6256565a516d383162585268556a527164334250517a6c4963585a4b536a5a4c4e46453364336c4651304633525546425955317354554e4e64306c525755784c64316c43516b4648517a565364304a4255564646525764525555464252554e4264314647516d646a53554e5262307845515442505248704253304a6e5a33466f61327050554646525245466e546b6c4252454a4751576c46515445354e4442744d6e426865485a615645355251584e4953544678516d68756255737253335a564e7939704d6b52714b306c50623239775956564453555a6c4d453945515739584f4735484f544a74654531694e6d314a4e324e354c304d355a6b4535565445335755687161334673656b6b7a623273695858302e65794a68634778445a584a3061575a70593246305a5552705a32567a64464e6f595449314e69493657794a4d5132457759544a714c3368764c7a56744d46553453465243516b3543546b4e4d57454a725a7a63725a79745a63475670523070744e54593050534a644c434a756232356a5a534936496b4e4c544856715958413157444a475346566e61537444636b353153473072556c4a7456484a4b566c5642656b46504f5667305569746c557a513949697769595842725547466a6132466e5a553568625755694f694a6a623230756558566961574e764c6e646c596d4631644768754c6e526c633351694c434a6959584e7059306c756447566e636d6c306553493664484a315a53776964476c745a584e305957317754584d694f6a45314e546b314e6a6b794d7a67334f545173496d4677613052705a32567a64464e6f595449314e694936496b7844595442684d6d6f76654738764e5730775654684956454a43546b4a4f51307859516d746e4e79746e4b316c775a576c48536d30314e6a5139496977695933527a55484a765a6d6c735a55316864474e6f496a7030636e566c66512e54672d627854616c77687a78794c52415837576c66432d595a4e3670484a56434b4b6a5952556d6331467166496e45396a335847636f32596b697974306c4456635266494934314d4c7134464733585f4c476773553649344d323572706e69796b5f64706278684e486655564c4c326d4b4f314546704d4b6d51787549644d51584f33635f31746a42386f6279334c524179545652366a337144463449495f676b466a69755a5a4b42715741746b66694f636f78506b3559474d452d6f525968694e6879457063446650376a5963365443414861682d714c5337696a7a5a48736c6a504a326f6c534e7a593673587550316b544650475744496d4e5647616f795f4a63576a626e476c705f585932506e46716f6247424a49714d43446354674f344330335934746879387343557849365f484f43754c694b6d5a3268536554673076544873635052744c444733755969464d65355051ffff")
      ),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(attestationMaker =
          AttestationMaker.androidSafetynet(
            AttestationSigner.selfsigned(COSEAlgorithmIdentifier.RS256)
          )
        )
    }

    val FalseCtsProfileMatch: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject = new ByteArray(
        BinaryUtil.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f0020a3c7abed63a16885b1cbf572b1bb29c6614812a886c222a00e07bc7c600764e4a52258209ab2b20ef874f994a3f99ad8f1e61ba590cf67357e5c0997dafcb71edf42ff9b0326010221582027834a6fcb02f7d3182bad5f2b3d16856c93fb574703503a847a36e457996275200163666d7471616e64726f69642d7361666574796e65746761747453746d74bf6376657268313437393930323168726573706f6e73655907e765794a68624763694f694a53557a49314e694973496e67315979493657794a4e53556c4463565244513046724b32644264306c435157644a51304a55613364445a316c4a53323961535870714d45564264306c335957704662553144555564424d565646515864335a466459566d6c685630353253555a6b62466c72526a466b5232683153556857645746595557646b52315a365a45684e5a31457752586845656b464f516d644f566b4a42623031436247777857573173616d4a3652576c4e513046485154465652554e33643170525746597759556457645752486247705a57464a3259326c43516d5249556d786a4d314a6f5a456473646d4a715255784e515774485154465652554a6f54554e564d4656335347686a546b31555a336450564545795456526a4d4531715158645861474e4f5456526e6430395551544a4e56474d775457704264316471516d5a4e556e4e335231465a52465a5255555245516b706f5a45685362474d7a5558565a567a567259323035634670444e5770694d6a423452487042546b4a6e546c5a435157394e516d78734d566c7462477069656b567054554e42523045785655564464336461555668574d474648566e566b5232787157566853646d4e70516b4a6b53464a73597a4e536147524862485a69616b564d54554672523045785655564361453144565442566432646e52576c4e5154424851314e7852314e4a596a4e4555555643515646565155453053554a45643046335a3264465330467653554a425555524d5a47317863474a616244687162454d3254304e364d484e7052475a7a4d48525157455644536a4a6e5230465253304e504d474d7261303832597a4a6d536b354b53473479617a427661553534644468595a4859794e6b704a5479394c555538764f4649794f55394b595567305233677a6247463656336c7065574d765a6e5651614845775a6a645a4b31686c536d354f575374494d3039365a4770534d474674575667345430565763565645526b74316358467862444251536e6c7a4e6a4e31516c70505548563256585a5556793931626b395a5430706d563352725655393563446c6d593235725a6d354c5230646e51326477574756485547786861486b3165455a465333564b4e6a4673536e565063455a5361484a725545737a596d78424f5455785745466f576b4e744e31685252444e4856323578636d687361546834567a4a79546a424b4f585a7a4e6a524b4f453169526d46724d465673546d353561305261623342724d46706a5746464252556f30545664595231527a4f44463554465a574f544e425931597261464e48534642545a3370334f4731564c32784d4f456452553235455530686a527a4251526c7042595456524d32704661307852536d59345745466e54554a4251556471536c5242616b31445255644465584e4851564652516d643156574e4255555646516b4a4a5255564251554a425a303146516c465a53454e42613074446433644f5247633464304e6e57556c4c6231704a656d6f77525546335355525451554633556c464a5a324d7a56316c5856533936596e6c3151334e6d6345704f4f544a46575563766457644b4d6c70564e31564b4d57526b4b324d76576b645252576444535646456232733461336c565a6a4e32535374735456687a5a565a57645452754e5667315332314d636b3575566b68485757566d4d326c565632457251543039496c31392e65794a68634778445a584a3061575a70593246305a5552705a32567a64464e6f595449314e69493657794a4d5132457759544a714c3368764c7a56744d46553453465243516b3543546b4e4d57454a725a7a63725a79745a63475670523070744e54593050534a644c434a756232356a5a534936496b59354d5559354c30526c616b49345a6a4a31516c646b596e425764557076655764346257744865486c77576c52516256646d625746695a57733949697769595842725547466a6132466e5a553568625755694f694a6a623230756558566961574e764c6e646c596d4631644768754c6e526c633351694c434a6959584e7059306c756447566e636d6c306553493664484a315a53776964476c745a584e305957317754584d694f6a45314e546b314e6a6b794d7a6b794d545973496d4677613052705a32567a64464e6f595449314e694936496b7844595442684d6d6f76654738764e5730775654684956454a43546b4a4f51307859516d746e4e79746e4b316c775a576c48536d30314e6a5139496977695933527a55484a765a6d6c735a55316864474e6f496a706d5957787a5a58302e415a6938386e4264644c315a4d336c4c6a654943724332384675386a657063573937686e79446a4d327a366b7870322d49514c484d3779706468674d424c386b307a6637436572647272634c4e63345671494f7a694a694677334752704a656a4a61625f65734d7137324f71742d3855727a48506849476d494251744347547647646577654551715453656131784f6b356576786a4f667630564571563272497263562d46445f5568527437586e38654479536658744e4254784a4765374a727858436b537061374f65465932577a4d6d76536e316c745f482d507a35784b6a5f6665564e34317362425a4e70624649496c724879324e4361374e676c5a50347a6948373769766979316e564f4977517a5866545a496b6b6f7434426a775630484a6557776a447166577375726c467578346b32715047327a6a41574b755a575877617137584751565f53687068384f38652d4d4977ffff")
      ),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(attestationMaker =
          AttestationMaker.androidSafetynet(
            AttestationSigner.ca(
              alg = COSEAlgorithmIdentifier.RS256,
              certSubject = new X500Name(
                "CN=attest.android.com, O=Yubico, OU=Authenticator Attestation, C=SE"
              ),
            ),
            ctsProfileMatch = false,
          )
        )
    }
  }
  object FidoU2f {

    val BasicAttestation: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject = new ByteArray(
        BinaryUtil.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f0020e50fe8ab67d1e773463decf62cfe9a9d5928ece4fd98a013b80478301bb8e29ea5225820d06403b07cf09311ca10b2478979deaaad9c65751e749c503fe9fb935686fcae03260102215820bfa61c3ae256f6a887d2ae9b2075b5246896ba9f44a2a6874ab746acfe7db9e3200163666d74686669646f2d7532666761747453746d74bf63783563815901eb308201e73082018ca00302010202020539300a06082a8648ce3d040302306a3126302406035504030c1d59756269636f20576562417574686e20756e6974207465737473204341310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a30673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130253453059301306072a8648ce3d020106082a8648ce3d030107034200040bd659232377a4f910fdcfccaec55511d00beacbdf417f49c9de938137f98df03971b3553bc11a2bd4ef5089ed290d15cc84e005443c794b13dc5e230916c591a32530233021060b2b0601040182e51c01010404120410000102030405060708090a0b0c0d0e0f300a06082a8648ce3d04030203490030460221008546464190caa7a603cd5c8dd60f30a23a9d227ca69603c1421c179092d8e4a1022100891b766c83b9def81518e354db14068d0ade9c8651927b347f4a63454b12add36373696758473045022100c88c93d88194e183f5522ec471a77f8a78d82fa7f99292f8d5f0c20cec6277d702203e289df8dd0568d9bd0b7d294fd30afcf3b264f5fb63f3163b46bb725c8fb31fffff")
      ),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(attestationMaker =
          AttestationMaker.fidoU2f(
            AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ES256)
          )
        )
    }

    val SelfAttestation: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject = new ByteArray(
        BinaryUtil.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f00205558386f4ed61a6c98a3fed94060fff66808947953754a0dff2aea9ae2164635a52258208d05cb87cec921d5e6fbc22c32a07fb35ed89c19a3f0a2866fcf4a248194e650032601022158202bb1c0846fca809059b41272f0c2953d733b31b50c14453b7a9855b7bfc98229200163666d74686669646f2d7532666761747453746d74bf63783563815901e7308201e330820189a00302010202020539300a06082a8648ce3d04030230673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a30673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130253453059301306072a8648ce3d020106082a8648ce3d030107034200042bb1c0846fca809059b41272f0c2953d733b31b50c14453b7a9855b7bfc982298d05cb87cec921d5e6fbc22c32a07fb35ed89c19a3f0a2866fcf4a248194e650a32530233021060b2b0601040182e51c01010404120410000102030405060708090a0b0c0d0e0f300a06082a8648ce3d0403020348003045022100a91c5499a6518bc59648bde7e7467488736e1ae82b5eb85c14957a0f82d23dfc02205a4b9963f88dbabaa0fa298eae6f0876b9f5e65650c4bd29f1f3f7eeb1312c24637369675847304502205af7085152ec65cc5ee097c5890316e6cac286379c32925a969ab414b013aa59022100b9b9d56cf4314e10c13caa57fb1fb0a01e87ffdec623c62637fddf56a8c4c62cffff")
      ),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createSelfAttestedCredential(
          AttestationMaker.fidoU2f(_)
        )
    }
  }
  object NoneAttestation {
    val Default = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject = new ByteArray(
        BinaryUtil.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f002082e7622c8c35a5786e66815f44a82b954628df497361169e77af23bb9bea1b69a5225820ae947a15818d883351ac00b957ad794c4b0206e2df34ec7b52969016a215800e03260102215820763f33278817151fad81d172493b8826c3a736cb1acf884e38c26fbe65c2438a200163666d74646e6f6e656761747453746d74bfffff")
      ),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() = TestAuthenticator.createUnattestedCredential()
    }
  }
  object Packed {

    val BasicAttestation: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject =
        ByteArray.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f00206b1549b3cf2524c30089b001f8a0f100de9a97681910d2c8181337c516cb2eb6a503260102200121582079c229789b5a262e7b3b2057ef8636b7a20930f262fac3636682e70bdcd4d906225820ca5084617d404d831791a8281eba451aa165726267f9d480dfc315313c95408d63666d74667061636b65646761747453746d74bf63616c67266373696758483046022100f1b2138ab5e8dbce9d0e88862295f574c1b636aa740b57d6705646c799084dd5022100d87f9df13302b854a1c6a726481afbd96ddd2caeb51f4cba89bd248676e9af1063783563825901ed308201e93082018fa00302010202020539300a06082a8648ce3d040302306a3126302406035504030c1d59756269636f20576562417574686e20756e6974207465737473204341310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a306a3126302406035504030c1d59756269636f20576562417574686e20756e6974207465737473204341310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130253453059301306072a8648ce3d020106082a8648ce3d030107034200043c010b106a69efe039327ab79f57f8e43285f59ad56a50cfd0264b8ba88f79bf2291d561768bb686431aadce9dddf56858aac55b1638d5c03d2a2c426b64b64aa32530233021060b2b0601040182e51c01010404120410000102030405060708090a0b0c0d0e0f300a06082a8648ce3d0403020348003045022100aa1943235627b47852deace94c46e2499a4b2bcab17ffe5502d0c5d17f0f883d022076402b6fe8f66040e4f157e74f732e4a4d31268115e2880faa999f248a0485e05901db308201d73082017da00302010202020539300a06082a8648ce3d040302306a3126302406035504030c1d59756269636f20576562417574686e20756e6974207465737473204341310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a306a3126302406035504030c1d59756269636f20576562417574686e20756e6974207465737473204341310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130253453059301306072a8648ce3d020106082a8648ce3d0301070342000448f77f8679a4c7bfff4a3ec8291f18995444d21b8624aeefdf2821e69444ac66ced7c7c10ea30d9167836ee84042a9b944d2c239f2a493d5fb2896a2ca0b83d0a3133011300f0603551d130101ff040530030101ff300a06082a8648ce3d0403020348003045022100acc2e79b65faaa5206b27714102f8cdb95ee656c567b7ae7511467b6c324e8e802202a5ac41e505ac43f9efcf3985db215a7506244ba67eb19bdf17aabef8773e1c1ffff"),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(attestationMaker =
          AttestationMaker.packed(
            AttestationSigner.ca(COSEAlgorithmIdentifier.ES256)
          )
        )
    }

    val BasicAttestationEdDsa: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.EdDSA,
      attestationObject =
        ByteArray.fromHex("bf686175746844617461588149960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f002089b13dc1075db05f34ea0f2e2fd843ce0c0b262a4a852f5eb03d3b2668f437dfa403270101200621582051be73800d9386b8bcfa03f80143ed1279486f95acb714515616b849b588298963666d74667061636b65646761747453746d74bf63616c6726637369675846304402207ef99a22fb1d6fac37ce859f768a3b3d85477ef3825ea53fb7824bb292b12139022073ba899784179bcd06fb3e75657a99cd710ed84a98edbdc8370ac9df885eb8bb63783563815901e7308201e330820189a00302010202020539300a06082a8648ce3d04030230673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a30673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130253453059301306072a8648ce3d020106082a8648ce3d03010703420004ba072ce8a10f63a776c3ce83972e20259089b0d2072501678daedaea755175ee34c785c7cc47e06561fac2b48b1f22e795173c4b89cdfd651a661bb7b9b180f1a32530233021060b2b0601040182e51c01010404120410000102030405060708090a0b0c0d0e0f300a06082a8648ce3d0403020348003045022100b75626efe7b98fb81dcf8dbb301a2a2a0dea354c5b43592368bb0b7345e1e6ea022003deb0739996db0c3a3b40c116f070d10d03e7261459426378fa2896a92e5024ffff"),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
      privateKey = Some(
        ByteArray.fromHex("3051020101300506032b657004220420098ff1cf173564547f5631f6db3f8dae75713b99d486604e8a09c755c53e11ee81210051be73800d9386b8bcfa03f80143ed1279486f95acb714515616b849b5882989")
      ),
      assertion = Some(
        AssertionTestData(
          request = JacksonCodecs
            .json()
            .readValue(
              """{"publicKeyCredentialRequestOptions":{"challenge":"N3LjI2J5ylyWe3ED5OT4XHLRqHwm_J48_D_hoJOFf30","userVerification":"preferred","extensions":{}},"username":"test@test.org"}""",
              classOf[AssertionRequest],
            ),
          response =
            PublicKeyCredential.parseAssertionResponseJson("""{"id":"ibE9wQddsF806g8uL9hDzgwLJipKhS9esD07Jmj0N98","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MBAAAFOQ","clientDataJSON":"eyJjaGFsbGVuZ2UiOiJOM0xqSTJKNXlseVdlM0VENU9UNFhITFJxSHdtX0o0OF9EX2hvSk9GZjMwIiwib3JpZ2luIjoiaHR0cHM6Ly9sb2NhbGhvc3QiLCJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwidG9rZW5CaW5kaW5nIjp7InN0YXR1cyI6InN1cHBvcnRlZCJ9LCJjbGllbnRFeHRlbnNpb25zIjp7fX0","signature":"-8AKZkFZSNUemUihJhsUp8LqXFHgVTjfCuKVvf1kbIkuwz5ClZK2u562C8rkUnIorxtzD7ujYh1z4FstXKyRDg"},"clientExtensionResults":{},"type":"public-key"}"""),
        )
      ),
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(
          keyAlgorithm = COSEAlgorithmIdentifier.EdDSA,
          attestationMaker = AttestationMaker.packed(
            AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ES256)
          ),
        )
    }

    val BasicAttestationRsa: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.RS256,
      attestationObject =
        ByteArray.fromHex("bf68617574684461746159016849960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f00202d027aec938e6fcf40460eb328f8596e43af1cbd99fddf61c1ffae6e7b0e404ba40339010001032059010100ab8f0b1c4ceef20c093cd67fe6cc264e3ba8208467f410e53b22415ef201ad1ad525ac1be334926ce4f565cfc777135924c1a9bfc3fad24e3d504d618602937b200fd1972ea0097ff9e7d33f68633263a8ce347550213de95228c9c093ca700042f782eb6c16da1b75ed2f481815b04c222cae865340592deeba809fee80e6c1199a3e36b50b400ef87570234754566b276a8fb0cbca7a6ffa1d24369878c8c831e415747b3142cce244ae8d4e0df921a4c9400ed615c1e9c98479af90be09fb2880512bf9d52f825ea031ff10daac369862df3da0d1a2782888415430d8040a0671a749269dcdc4ac22a66b42cf0ac3a3365a64c6ce82ff2548bfac493f6bad214301000163666d74667061636b65646761747453746d74bf63616c673901006373696759010054de4d2aae25f9bd1b9d0e20a9d4168a5feded7178fe1f47ee0fb9a8f19439c8cc1aeab7a7269e4d4edb29c7c9864fbd8202d8cc69584da0e73b4c1d731bff3ec29599964ebef12068a9791d0e52a0c9579d881c565e1ae8a0fc7f2de9ec8882d13919a164b362ab2a89faec3be869635f187b3ef30cd20986ec6f2ff667cb1a279871f77dd9d037f49a7da784cdf846e2d7220683aa928e3b422616be8b0609385a16e0509365a609e162a5239bdc1c4e7aa60c9a1860de753b99705173a72c9fc0390f42886ff9ff839f045cf6457ecb7cf26da34e95511fde6343e4812f40ceb8ff2e7dd24dafdd9c513225bf3418df4a7c1c0f5bc6a0155a31d9c2ddfe8c63783563815903733082036f30820257a00302010202020539300d06092a864886f70d01010b050030673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a30673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b300906035504061302534530820122300d06092a864886f70d01010105000382010f003082010a028201010097c332c418daf7cb31e27bf321f7f72f48c614650f6215db969d17a6ba24fc08d3140fa4d45ff2b2b0ce95fbd87b629e23ba84533dbf2ed90c4e2a770db459690ddfa433288a06fa0c2b1c012887926f1d366d2beac622788560d0a4197b4d90ba7bfd6f4b3250cc37f54e5f350160ad61136bca94b560ec783334cf0376cca042ff40b288049881f7fb3c265f6bbfd625c18efe5802c7dbd384b0b6f328ae9a1bbeb4a184b8eddf16ff419a76adef00d20b57e0927e997c2dfec964c24fb2f023848916c41b0de26636be72356b555d4d1090f2cbcf9003eff39d4b6f77498481d6fe8b2f2bfe2e895382494ca4495c8ac9a47c9fbc8832dc66f727852f814d0203010001a32530233021060b2b0601040182e51c01010404120410000102030405060708090a0b0c0d0e0f300d06092a864886f70d01010b050003820101002a801c27a9a78f74db8de08bc367a8877f53007c7edc01354716be772d7e1450ab99c7b9d4e1c30c05080e51cc69c98068f0130aeccea535e1eb4e7834413bba888633a0c3aad9b7286096084425500b8b442a30ffd52cb77520ee28e8341e2640c39b81be07d9fce48d49ee3bad11b6015c78505e2c1aeaeb829c167bd86bbb714310f6559f481bb9b970dbe8184c7b24d8a4ef2030331d6c8d41b966d5fb4bf08f8f736adedc918fe039100330a5c6a79c54c92351c907608abda0fc98f019ac182ed2858f3c65aeeb282562d1036a06573edac5bed696553b5d347620cf9412faddaab3319080263378085812b315357a3cbe3618ff81d2760c7276ded4afffff"),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(
          keyAlgorithm = COSEAlgorithmIdentifier.RS256,
          attestationMaker = AttestationMaker.packed(
            AttestationSigner.selfsigned(COSEAlgorithmIdentifier.RS256)
          ),
        )
    }

    val BasicAttestationRs1: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.RS1,
      attestationObject =
        ByteArray.fromHex("bf68617574684461746159016849960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f00200dccf988353c4ba273b0cb871029fcfd3ea2ba0474a3c8aa34120cdf386d41f8a40339fffe010320590101009dc7b1317f0d4791afa7312dc4189fa272d7891853d48bd93064057c785248a0592cf2dcc3a31430218bd960f4ab7df989f142f4ab31dd4e481b28cf8e715656d07b3ecf1d88b6a2621f4bed5972e18be692ef155887cc0d03e200d0e5144995c1c1eee75cd68ad625c586dbfc2beeedf911615bbc7c0f14933a46c9bf4506f14337fec3ef57dccda236e4df1d83aad4bcd53ff9e754da7775bd45a09447483173ae265bee5560960fe581ab5a29b57ebbd10c2b07406ba259cbf20e7b22d96dafcdfb9b2d475853d3d5ccb6e619994f2ba6ef112165cae2db9d608f6c68dfaabae056dc19f933080d26c29dbe47dcf88a5435e9582df63e5f24dc35ac1fe88f214301000163666d74667061636b65646761747453746d74bf63616c6739fffe6373696759010008003116f6b02c14a059d8a0e92fdb5653b0c459528761cfbb2d34a192d12247ca9cfe7f164322ea38db77e9ae470d85ff00a892bab69dfb06b71bcda93b3b8c8beb1a530cfbbfa06f021e78230a31f5554f9547e34c1f9a47fb1cba3d76871796d92c5ee98ac367740d8ec36fe58dc9fdcb0e6a343880d83e1efa02895924278ecdf20a6803a2ac2c0309166346a8325ad6068a066fc12997df73ea0c0e32d05ecedc5d4c6de917fc1bc8e8cbc910a17e87159dc73552d8788477410d271e42fa261cc22c1d8edd464b3d082452b16dc5b19e81426b6bf7ab7de362faffc1697a9b23b971301f50fe38596b453bd614c04dd9a75f1e0aa1d38153e2e5a9268363783563815903733082036f30820257a00302010202020539300d06092a864886f70d010105050030673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a30673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b300906035504061302534530820122300d06092a864886f70d01010105000382010f003082010a0282010100d22a48cd3bdc9fa809a24a04dc158976b089296e54a949b29b7092dd5f16d2db81ffac4c814e2aaaf0be4f7e8214227ceb30cfe5da668d442999a40be8b2525b449084e7b5bdc3f29f16e303d3610500851e4d32053b1b0397ea285fa60a035df598618b5d67b2d1d8631575edc6d9de7873f4fc3156be00a59815adb226cfc274c86075bb3ff00d9e17bc1114220f91c23707ff415917ffaf34320845f50a01464a7b191385d8cac693ac68c26ed5589bec92f9db757df64bb025085bdee285f3b88e49d959f7ecaf0a70fbf5a3815bdb947bca995ac21c66d765ca380d8d348da06292375f7a8e9d5919a25f96168e61e67d097b7727eeca3645bf039fd4590203010001a32530233021060b2b0601040182e51c01010404120410000102030405060708090a0b0c0d0e0f300d06092a864886f70d0101050500038201010030d14a17813ccd2e2374300525cbbf6e55cb2f0b7e83fee0cc7345addca2cc139d40bba79846739630a9d60959d74eec2d2ea1015a6ec3fa9660be494b5efe80b3888287c6e275f4121f6b7dd076850de8e85538576ce44a71fd487f1dba264350dc1926eee25968c69556db43f4821272385e46c44715e3a7d603d5f6f3ae46abee46abb89070bd4628d4165b8c34bb77854b9b03a37efe3bf9220cc2ef1c4ae88c820eae5e984fbd54a280358d5198cdd3bd6bf54ab14c2253abaa59cd607769b71e8ed7b5a9b0a80d96002ab0cec9f0c5b387bcf44ea3a5b53f421a0ae8035be68e3c9afad1f6328afe05ad2a90407aa2778e1ea88062b0834dde1baf14d6ffff"),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
      privateKey = Some(
        ByteArray.fromHex("308204bc020100300d06092a864886f70d0101010500048204a6308204a202010002820101009dc7b1317f0d4791afa7312dc4189fa272d7891853d48bd93064057c785248a0592cf2dcc3a31430218bd960f4ab7df989f142f4ab31dd4e481b28cf8e715656d07b3ecf1d88b6a2621f4bed5972e18be692ef155887cc0d03e200d0e5144995c1c1eee75cd68ad625c586dbfc2beeedf911615bbc7c0f14933a46c9bf4506f14337fec3ef57dccda236e4df1d83aad4bcd53ff9e754da7775bd45a09447483173ae265bee5560960fe581ab5a29b57ebbd10c2b07406ba259cbf20e7b22d96dafcdfb9b2d475853d3d5ccb6e619994f2ba6ef112165cae2db9d608f6c68dfaabae056dc19f933080d26c29dbe47dcf88a5435e9582df63e5f24dc35ac1fe88f02030100010282010001c33bc5aba41e31d9be5cd7db5489609437010f38a8871124cb1b8c02db8753521e004a48825e505e31db9f1dcee8a5cc9690675a79ae46cf75fac8e119362e6d3eac5f1964a6e23dceaad77aad0d7291166e46c2a0dc07240d3fdfa7d65a53861c77865a714cd931071e506d665688453279cb88b5173c52e4bcc5ff5a4e7d1a25ec361c703f032a0f927a33348779bdc877b206d19c71b3851d572417206d76a605cdadd3f4701c76d98bb77d3c0daa516219cda1a1378ff1bc57e5a53d2ca4acaea01a4ba3daa1436d0b6e5773ad25711802d974e3bdcfafee572cd5cc4690a8aa861a64d110cdb108be6b5de2d2f575adaa8f8a6a4379581da7ad70f86902818100d71c1b9085370c186c92ecf0c9665c84caf7308b97c47b6e8c42b7e7de2ef0b904228d59a7285fec01f181f76039bba36177d89eff2ea5109e1d8267ab85b88e20d988d9ceee81d2d86f373fc52938549b944ac21eca3329e8b629afb557d28258753d19fd429cf84983fdc3335dab622330a4e0051de4ff707db659ed6fefcb02818100bbc5beeca7fe242ec3e4d1193f6df05bfe1516ccfd0577008863533d3b2be42d2ebd0a8d6bd172edf8eff30462b3beb31cbddb449853b6de0d58eb4269b7374ae80dd189c0243ca8da1d19097359784bf124dd92949b460e90b075469a676da2f00c94382cf9b5b6afa9828f4706331720bc12d37463812019812f6bded449cd028180429d12b02b80c37f20c85315b1d8c017e35eaf2adb61de337abe02838c5b8ef24ca4828f5be375e8f92517f14a5c368e3ed5c5405f97cb481d1ed84e506085a985e4b7ab73988a9d87a6d13e2f49378783f265403e16b1c76da853ba74f6f05aab180b46ec15dfd447b7d732c6ca60137100545e87571d9e38f0c5328e03d70702818049b32ce4006ffccdaa2fd66e7d79ee3c7d36d3d33380809be1ec725077381c002bf720fc2f146f72be219815e193c146d60222dd0298e10eb8d86cc68d6dcf33046fe00d9c2fdceb3d68ec59cc3f92bae3f45f4f582ab5cda3b6cee11e5b7829dae4650cc382637347f155805d152eda660bcbabd963f0dba3871410d7ce250502818039ee632c8dc74bae5b99b28d2c53c80934709101aa2c64f696d23f53842074814b023e579525105ffac163a6b22f25c5ff4b5a2961d12eca826f7ace40af34c0c5563ba6103d119e93cc900fbbe9f12677f6eba80598d305af3d706a625250c991a1bf3f8b149aec248777ecc0c52f56b44980a5c994d4b9d9f4f74aa4464b80")
      ),
      assertion = Some(
        AssertionTestData(
          request = JacksonCodecs
            .json()
            .readValue(
              """{"publicKeyCredentialRequestOptions":{"challenge":"N3LjI2J5ylyWe3ED5OT4XHLRqHwm_J48_D_hoJOFf30","userVerification":"preferred","extensions":{}},"username":"test@test.org"}""",
              classOf[AssertionRequest],
            ),
          response =
            PublicKeyCredential.parseAssertionResponseJson("""{"id":"Dcz5iDU8S6JzsMuHECn8_T6iugR0o8iqNBIM3zhtQfg","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MBAAAFOQ","clientDataJSON":"eyJjaGFsbGVuZ2UiOiJOM0xqSTJKNXlseVdlM0VENU9UNFhITFJxSHdtX0o0OF9EX2hvSk9GZjMwIiwib3JpZ2luIjoiaHR0cHM6Ly9sb2NhbGhvc3QiLCJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwidG9rZW5CaW5kaW5nIjp7InN0YXR1cyI6InN1cHBvcnRlZCJ9LCJjbGllbnRFeHRlbnNpb25zIjp7fX0","signature":"g3lWw0SG1AkAaxelbkPnrYvBBRg8VQZIkNHBp6Ogn-2E2zOan8Xe_FBItM_P1K_p49G9SpsljIrQxakH1kZMGBMflHYyaJC1duX0wqgUdFwz_p3sEfo9_vYpXt_Ytj6QYCOUjlJav_eGhtA_K-AWrw3Gz74nUrnjiBaFw-Iqno9ZucpRDo_0vKuTb7ARDSOWYo0eHWzcfY3CvXuEVxDlamUeA_JRtM2t4BKFaUo_91_D4XIvGO9KBWdM0d3KaU5hotO6kLjk0-EdQHrBNSweU0KeJEqBlceFj4AiPN8RFot5qXq1w_Zs9orLME-HwvkVykAGRZSdu2Pcjr2tNpQohg"},"clientExtensionResults":{},"type":"public-key"}"""),
        )
      ),
    ) {
      override def regenerate() =
        TestAuthenticator.createBasicAttestedCredential(
          keyAlgorithm = COSEAlgorithmIdentifier.RS1,
          attestationMaker = AttestationMaker.packed(
            AttestationSigner.selfsigned(COSEAlgorithmIdentifier.RS1)
          ),
        )
    }

    val BasicAttestationRsaReal
        : RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.RS256,
      // Real attestation object from SKY3
      attestationObject =
        ByteArray.fromBase64Url("o2NmbXRmcGFja2VkaGF1dGhEYXRhWQFXAU4Ai_91hLmkf2mxjxj_SJrA3qTIOjr6tw1rluqSp_5FAAAAAG1Eupv27C5JuTAMj-kgy3MAEApbxn7DR_LpWJ6yjXeHxIGkAQMDOQEAIFkBAPm_XOU-DioXdG6YXFo5gpHPNxJDimlbnXCro2D_hvzBsxoY4oEzNyRDgK_PoDedZ4tJyk12_I8qJ8g5HqbpT6YUekYegcP4ugL1Omr31gGqTwsF45fIITcSWXcoJbqPnwotbaM98Hu15mSIT8NeXDce0MVNYJ6PULRm6xiiWXHk1cxwrHd9xPCjww6CjRKDc06hP--noBbToW3xx43eh7kGlisWPeU1naIMe7CZAjIMhNlu_uxQssaPAhEXNzDENpK99ieUg290Ym4YNAGbWdW4irkeTt7h_yC-ARrJUu4ygwwGaqCTl9QIMrwZGuiQD11LC0uKraIA2YHaGa2UGKshQwEAAWdhdHRTdG10o2NhbGcmY3NpZ1hHMEUCIQDLKMt6O4aKJkl71VhyIcuI6lqyFTHMDuCO5Y4Jdq2_xQIgPm2_1GF0ivkR816opfVQMWq0s-Hx0uJjcX5l5tm9ZgFjeDVjgVkCwTCCAr0wggGloAMCAQICBCrnYmMwDQYJKoZIhvcNAQELBQAwLjEsMCoGA1UEAxMjWXViaWNvIFUyRiBSb290IENBIFNlcmlhbCA0NTcyMDA2MzEwIBcNMTQwODAxMDAwMDAwWhgPMjA1MDA5MDQwMDAwMDBaMG4xCzAJBgNVBAYTAlNFMRIwEAYDVQQKDAlZdWJpY28gQUIxIjAgBgNVBAsMGUF1dGhlbnRpY2F0b3IgQXR0ZXN0YXRpb24xJzAlBgNVBAMMHll1YmljbyBVMkYgRUUgU2VyaWFsIDcxOTgwNzA3NTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCoDhl5gQ9meEf8QqiVUV4S_Ca-Oax47MhcpIW9VEhqM2RDTmd3HaL3-SnvH49q8YubSRp_1Z1uP-okMynSGnj-jbDBqMCIGCSsGAQQBgsQKAgQVMS4zLjYuMS40LjEuNDE0ODIuMS4xMBMGCysGAQQBguUcAgEBBAQDAgQwMCEGCysGAQQBguUcAQEEBBIEEG1Eupv27C5JuTAMj-kgy3MwDAYDVR0TAQH_BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAclfQPNzD4RVphJDW-A75W1MHI3PZ5kcyYysR3Nx3iuxr1ZJtB-F7nFQweI3jL05HtFh2_4xVIgKb6Th4eVcjMecncBaCinEbOcdP1sEli9Hk2eVm1XB5A0faUjXAPw_-QLFCjgXG6ReZ5HVUcWkB7riLsFeJNYitiKrTDXFPLy-sNtVNutcQnFsCerDKuM81TvEAigkIbKCGlq8M_NvBg5j83wIxbCYiyV7mIr3RwApHieShzLdJo1S6XydgQjC-_64G5r8C-8AVvNFR3zXXCpio5C3KRIj88HEEIYjf6h1fdLfqeIsq-cUUqbq5T-c4nNoZUZCysTB9v5EY4akp-A"),
      clientDataJson = new String(
        ByteArray
          .fromBase64Url(
            "ew0KCSJ0eXBlIiA6ICJ3ZWJhdXRobi5jcmVhdGUiLA0KCSJjaGFsbGVuZ2UiIDogImxaMllKbUZ2YWkteGhYMElteG9fQlk1SkpVdmREa3JXd1ZGZllmcHQtNmciLA0KCSJvcmlnaW4iIDogImh0dHBzOi8vZGVtbzMueXViaWNvLnRlc3Q6ODQ0MyIsDQoJInRva2VuQmluZGluZyIgOiANCgl7DQoJCSJzdGF0dXMiIDogInN1cHBvcnRlZCINCgl9DQp9"
          )
          .getBytes,
        StandardCharsets.UTF_8,
      ),
      rpId =
        RelyingPartyIdentity.builder().id("demo3.yubico.test").name("").build(),
      origin = Some("https://demo3.yubico.test:8443"),
      userId = UserIdentity
        .builder()
        .name("foo")
        .displayName("Foo Bar")
        .id(
          ByteArray.fromBase64Url("NiBJtVMh4AmSpZYuJ--jnEWgFzZHHVbS6zx7HFgAjAc")
        )
        .build(),
    )

    val BasicAttestationWithoutAaguidExtension: RegistrationTestData =
      new RegistrationTestData(
        alg = COSEAlgorithmIdentifier.ES256,
        attestationObject =
          ByteArray.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f00209e5f31be46db4229e201138428cc52ee5cf95649af97192b0c0bd95c6bf7da42a5032601022001215820edd3776120e992e2917f67dea1bd9ab796d4766e1c8d7f158d12b0b2c4932ba4225820393783915791af3e5b4ee9a8be59f9fc36b8c95b084d2d44c0095572ad8ac90263666d74667061636b65646761747453746d74bf63616c67266373696758473045022100e4653ca6e7334f6043e95636bafe4f4ca17eecfc21bd17d7b849e4fc723d07560220389513d56b8c030e964d4a286acd3cc5f74aaf1665a84a06421ef23cc2db0a3963783563815901c1308201bd30820162a00302010202020539300a06082a8648ce3d04030230673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a30673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130253453059301306072a8648ce3d020106082a8648ce3d03010703420004b83a0a452140254924a85f18868222eef921abf3859a6c4bc1704c4a3a55131be3191da5c8f2bde0e3f7fc0042e3ced4821112139a085ccd331ab0d9a36ba2a2300a06082a8648ce3d0403020349003046022100a9542f7287013fdefd29edadb84ad61f5b90c938d315c4dbf72005ed2808b149022100d4235ec51d66d892ff9447585167f728ce87733a29e41bac97b437b45ee1571dffff"),
        clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
      ) {
        override def regenerate() =
          TestAuthenticator.createBasicAttestedCredential(attestationMaker =
            AttestationMaker.packed(
              new AttestationCert(
                COSEAlgorithmIdentifier.ES256,
                TestAuthenticator.generateAttestationCertificate(
                  alg = COSEAlgorithmIdentifier.ES256,
                  extensions = Nil,
                ),
              )
            )
          )
      }

    val BasicAttestationWithWrongAaguidExtension: RegistrationTestData =
      new RegistrationTestData(
        alg = COSEAlgorithmIdentifier.ES256,
        attestationObject =
          ByteArray.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d976341000005390f0e0d0c0b0a0908070605040302010000207b733c7c32c0303159eceb83a77e359de67b8aff51b4ae82af5e34e7b39b3a24a50326010220012158205d2702c2d02739b3a8bfbe84011cdf4c39b3dd1da73f92cb70c8ebe557ee277f225820d60faf92a4fcb6d49dbcbc59260d2fb031ce5c8a95f93d56553662bfa050ab0363666d74667061636b65646761747453746d74bf63616c6726637369675846304402201355a030930063732001ecbddf42e2b8de03ab3fbf96c492fd224929310c36e0022014704aa8426eb36229d5eb59db825f8184ad29ad1a3b6ab7f29a9a8304ea00de63783563815901e7308201e330820189a00302010202020539300a06082a8648ce3d04030230673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b3009060355040613025345301e170d3138303930363137343230305a170d3138303930363137343230305a30673123302106035504030c1a59756269636f20576562417574686e20756e6974207465737473310f300d060355040a0c0659756269636f31223020060355040b0c1941757468656e74696361746f72204174746573746174696f6e310b30090603550406130253453059301306072a8648ce3d020106082a8648ce3d03010703420004e2a3cd9d0a55a1204a3eb3681b793cc3251a28d948428111241359d6c45f5af1ba36a50e0b5cd1c3fd81974cddd9fdb4aba0fd1352e1e107721433b32f34c717a32530233021060b2b0601040182e51c01010404120410000102030405060708090a0b0c0d0e0f300a06082a8648ce3d0403020348003045022100e5818e204920da08899fb97942c57b792bd769c2bfbe7ccd5c25d2169b1588b402207b7446fe3b419d0a4850a87abf3679611086f83df605e908ad3026cd8695f749ffff"),
        clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
      ) {
        override def regenerate() =
          TestAuthenticator.createBasicAttestedCredential(
            aaguid = new ByteArray(
              Array(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
            ),
            attestationMaker = AttestationMaker.packed(
              AttestationSigner.selfsigned(COSEAlgorithmIdentifier.ES256)
            ),
          )
      }

    val SelfAttestation: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.ES256,
      attestationObject = new ByteArray(
        BinaryUtil.fromHex("bf68617574684461746158a449960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f0020fa616cbe1c046d224524e773b386f9f3fd0d0fb6d4c20700023288034e48f093a52258208b02052aeec1d7cfaf1244d9b72296a6bfaf9542c132273c4be8fc01388ee8f30326010221582081906607ef7095eaa3dea2517cfc5a7c0c9768685e30ddb5865f2ada0f5cc63c200163666d74667061636b65646761747453746d74bf6373696758473045022010511b27bd566c7bcdf6e4f08ef2fe4ea20a56826b76761253bbcc31b0be1fa2022100b2659e3efc858fd4389dc48cd0651487f2e7bc4f5eba59db154bdcd0ae60c9d163616c6726ffff")
      ),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
    ) {
      override def regenerate() =
        TestAuthenticator.createSelfAttestedCredential(
          AttestationMaker.packed(_)
        )
    }

    val SelfAttestationRs1: RegistrationTestData = new RegistrationTestData(
      alg = COSEAlgorithmIdentifier.RS1,
      attestationObject =
        ByteArray.fromHex("bf68617574684461746159016849960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97634100000539000102030405060708090a0b0c0d0e0f0020a8330648c97e09686004be4c429ad3e46886f6033117632cb1aabf261c5d11cda40339fffe01032059010100cdb2b9448221d1432be58b681f27ad204e82fe4c6176c64aed49792fe57c5ca9ddf7ce6fe22f81b67205df310d96668c1c1107ea6e250f4107692842c555c13d6e3df41ca701ce153705269658a186d9a1abe013b127dd51483323f3c82e281962eccfd4f59c05d778ecbbfbfb5eb5902dc91e1e187aacd97d42373a3c3e05218d291989133cf32641d322e6e472c3e4812e613d9ddbb67e74580570d5ef173561c146d81c56bf7bc6353fde611b54cd1fe632a314ac7d3e74ac18c0b7886a70ddcce226dd836791444a88ac9323877adbc5978a51d2abca189651ad5b71169df782f065908edd8ab9edccdc997212c32071b577fd58d55b22557d303d070b77214301000163666d74667061636b65646761747453746d74bf63616c6739fffe63736967590100bbf85e350e87886d80591e44b1a8e8f7fe7a4b3c4748b112ac6bbd88096a7b83c5e2f268154eecec230784729d6418809ce1ea370c374fd3e6151790d0a7f5a7a9e57dcbfd2e0cad26b11002232087eaaa0baf7fdef65c30518237d4ae7d36b7c49cc96b499afb6c0eab2c6a728fa847595071b56515c049d909707fbea2ee22ce0a325939af3b9021e1371bfea19cd14fc9caa1d1a41d5408cba381197c5fddc4e33245411d720c3acb4e53b415b120581d8093e25d710e5acef7e77889a71e5dee935f02992a559eab33725c832f3f24bf3934de2f5ac2eb32a9cc23a652bf08fc7e94c342ef62b555524b733447a19b3307fb41257794e041e91d1e1fbb37ffff"),
      clientDataJson = """{"challenge":"AAEBAgMFCA0VIjdZEGl5Yls","origin":"https://localhost","type":"webauthn.create","tokenBinding":{"status":"supported"},"clientExtensions":{}}""",
      privateKey = Some(
        ByteArray.fromHex("308204bd020100300d06092a864886f70d0101010500048204a7308204a30201000282010100cdb2b9448221d1432be58b681f27ad204e82fe4c6176c64aed49792fe57c5ca9ddf7ce6fe22f81b67205df310d96668c1c1107ea6e250f4107692842c555c13d6e3df41ca701ce153705269658a186d9a1abe013b127dd51483323f3c82e281962eccfd4f59c05d778ecbbfbfb5eb5902dc91e1e187aacd97d42373a3c3e05218d291989133cf32641d322e6e472c3e4812e613d9ddbb67e74580570d5ef173561c146d81c56bf7bc6353fde611b54cd1fe632a314ac7d3e74ac18c0b7886a70ddcce226dd836791444a88ac9323877adbc5978a51d2abca189651ad5b71169df782f065908edd8ab9edccdc997212c32071b577fd58d55b22557d303d070b7702030100010282010029573fb3fca17650d53c3399f01505cf05e87eda74062e9135827c483b8b94861155f217fb7207d456b34669b1ece5dc47f1c650ffe513dd427388836eecaec33d6a572b0107b45700315951832ba7920ad3a3dbe1517d420e4c34f0146dee6237c717781a0acb03c4ca73778fcc379a6c114d2bc848b37f9c9497cbecfa9c0607181290eda54e995999b2c18286ce3abba2d1a18f0785b76b163335fe1d7a805f1fe17ed592eabca18be4da7857bc384ec6398a5784e022e16dcd4e61dad8d285a475600d9f11d6e5aa7989a590ffbc99b45283282433e3e4f8d96d3f422c90c850ef3f906ba935dec95ce01f1192685d0e7ab3da7593aca13f4d2890cd112502818100fbe8098b0b37fd43c7b10bb49212e9e162e9be02d6c559d6a1e30a87d8dea7970ea76425226980c1d5bb63ddefcba787fcab8601e89d070dba758d3bf39f4407be8ad6e95abeb86c60be1939614c67720f75ab140837955e037812462733dd372e4751baa5fe87e074064e98d70c201342e9a4d47d6cb88fc6df5db6ac89e14302818100d10a744597179abf260100f7b295f24bed809f101f5a9b388bb04378665461b48c1016677768e6612690ce2f794428eba2a8fa0821f58f713be04b29aa83664f07b3b962c004a60286ad35c585ed4bacfe66682490f7ab7e62529232be325cebe52876e6dcef53373171861b7d40520f69b74c8620ffac0fe64623358a1effbd02818035f843bb277f2a62d030cd5a358599d83111f524b490f9ab7369aa42eaa2e1730aafb0540868642ea3350fb36801d0f5e09b7b0d83a1c8f61701c26d9ac77f92cd2effd6651bc1756ed0aba4d084c710f7e0f4f348c367dc09903b120eaa1cf60a933b1e6b1bfa4e8b6d227fba6b1da022d0de00ac929384324e7ecc7970dcf302818100cffcfdd92bcf419a04bf24ee4f53204469a7fb1bb886974078c4452d6b6b73d787308e8a1de652aac10b7d0b01364f1cbcb832269b5b4f8093d9c40f4de7f588969a3ccf434c9cbc90b19079da9a531c69f70c91ad67afcb4d1ae8f9f201fc307dce78179625cd7f720389329ab9bfac343c3bb88ce6b6950f4223d0268057650281800193dfb5d9612213bbdcbfd274061e5c02d439e2bcbecee0fc6cbe53b2c009b3c2b9438ee48e8c56af5703b12551bf3480761132fa483b26b024387397fd6e6e1f90717b84ce5a24bbccee01180ff113363e5c83c5fb49fa8475db93cd7fa79965853f5c196717ec2ef0047302a7943df5ba2cc462f5f5fc3068d1f72b15a565")
      ),
      assertion = Some(
        AssertionTestData(
          request = JacksonCodecs
            .json()
            .readValue(
              """{"publicKeyCredentialRequestOptions":{"challenge":"N3LjI2J5ylyWe3ED5OT4XHLRqHwm_J48_D_hoJOFf30","userVerification":"preferred","extensions":{}},"username":"test@test.org"}""",
              classOf[AssertionRequest],
            ),
          response =
            PublicKeyCredential.parseAssertionResponseJson("""{"id":"qDMGSMl-CWhgBL5MQprT5GiG9gMxF2Mssaq_JhxdEc0","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MBAAAFOQ","clientDataJSON":"eyJjaGFsbGVuZ2UiOiJOM0xqSTJKNXlseVdlM0VENU9UNFhITFJxSHdtX0o0OF9EX2hvSk9GZjMwIiwib3JpZ2luIjoiaHR0cHM6Ly9sb2NhbGhvc3QiLCJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwidG9rZW5CaW5kaW5nIjp7InN0YXR1cyI6InN1cHBvcnRlZCJ9LCJjbGllbnRFeHRlbnNpb25zIjp7fX0","signature":"YQuXZwJLOXeEfrOxzG42yJxShEGHFbfD2oYURkOiZOI2LSzfcv5t5KDq4dfJ9S-U5aaylfIlD72u8rQeMIVyf5e8jD5z0bnPP5STZzDsJneoPGOQ6BQfuYGSGSO_JxjU9O6KduNTXKrm2KqaCptOTJHyf9geA2wR7_XSmEdg_OSq7e164ZIK12jiG-RFdEEVpWhuoJPva0TeHfe2tAnQPNreV7v8DaIOWJiBblQTirP0oUn5LrCNhl_Tsgz2-F8R53k48JpesiMhEM6r-e7DI83CrNRZWJnmO-04hMEbdNqO3TmZ3Fmtw9ufpn3zygeK0jrIw3SamFe2NgVvbcIHTg"},"clientExtensionResults":{},"type":"public-key"}"""),
        )
      ),
    ) {
      override def regenerate() =
        TestAuthenticator.createSelfAttestedCredential(
          AttestationMaker.packed(_),
          keyAlgorithm = COSEAlgorithmIdentifier.RS1,
        )
    }
  }
  object Tpm {
    val PrivacyCa: RegistrationTestData =
      Packed.BasicAttestation.setAttestationStatementFormat("tpm")
  }
}

case class RegistrationTestData(
    alg: COSEAlgorithmIdentifier,
    assertion: Option[AssertionTestData] = None,
    attestationObject: ByteArray,
    clientDataJson: String,
    authenticatorSelection: Option[AuthenticatorSelectionCriteria] = None,
    clientExtensionResults: ClientRegistrationExtensionOutputs =
      ClientRegistrationExtensionOutputs.builder().build(),
    privateKey: Option[ByteArray] = None,
    origin: Option[String] = None,
    overrideRequest: Option[PublicKeyCredentialCreationOptions] = None,
    requestedExtensions: RegistrationExtensionInputs =
      RegistrationExtensionInputs.builder().build(),
    rpId: RelyingPartyIdentity =
      RelyingPartyIdentity.builder().id("localhost").name("Test party").build(),
    userId: UserIdentity = UserIdentity
      .builder()
      .name("test@test.org")
      .displayName("Test user")
      .id(new ByteArray(Array(42, 13, 37)))
      .build(),
) {
  validate()

  def regenerate(): (
      PublicKeyCredential[
        AuthenticatorAttestationResponse,
        ClientRegistrationExtensionOutputs,
      ],
      KeyPair,
  ) = ???
  def regenerateFull(): Try[RegistrationTestData] =
    Try({
      val (credential, keypair) = regenerate()
      val newValue = copy(
        attestationObject = credential.getResponse.getAttestationObject,
        clientDataJson = new String(
          credential.getResponse.getClientDataJSON.getBytes,
          StandardCharsets.UTF_8,
        ),
        privateKey = Some(new ByteArray(keypair.getPrivate.getEncoded)),
      )
      newValue.copy(
        assertion = newValue.assertion.map(_.regenerate(newValue))
      )
    })

  protected def validate(): Unit = {
    val alg = WebAuthnCodecs
      .getCoseKeyAlg(
        response.getResponse.getParsedAuthenticatorData.getAttestedCredentialData.get.getCredentialPublicKey
      )
      .get
    assert(alg == this.alg, s"Expected alg: ${this.alg}; was: ${alg}")
  }

  def clientDataJsonBytes: ByteArray =
    new ByteArray(clientDataJson.getBytes("UTF-8"))
  def clientData = new CollectedClientData(clientDataJsonBytes)
  def clientDataJsonHash: ByteArray = Crypto.sha256(clientDataJsonBytes)
  def aaguid: ByteArray =
    new AttestationObject(
      attestationObject
    ).getAuthenticatorData.getAttestedCredentialData.get.getAaguid
  def packedAttestationCert: X509Certificate =
    CertificateParser.parseDer(
      new AttestationObject(attestationObject).getAttestationStatement
        .get("x5c")
        .get(0)
        .binaryValue
    )

  def attestationCaCert: Option[X509Certificate] =
    Option(
      new AttestationObject(attestationObject).getAttestationStatement.get(
        "x5c"
      )
    )
      .map(x5c => x5c.elements().asScala.toList.last)
      .map(node => CertificateParser.parseDer(node.binaryValue()))

  def editClientData(updater: ObjectNode => JsonNode): RegistrationTestData =
    copy(
      clientDataJson = JacksonCodecs.json.writeValueAsString(
        updater(
          JacksonCodecs.json.readTree(clientDataJson).asInstanceOf[ObjectNode]
        )
      )
    )

  def editClientData(name: String, value: JsonNode): RegistrationTestData =
    editClientData { clientData: ObjectNode =>
      clientData.set[ObjectNode](name, value)
    }
  def editClientData(name: String, value: String): RegistrationTestData =
    editClientData(name, RegistrationTestData.jsonFactory.textNode(value))
  def responseChallenge: ByteArray = clientData.getChallenge

  def editClientData(name: String, value: ByteArray): RegistrationTestData =
    editClientData(
      name,
      RegistrationTestData.jsonFactory.textNode(value.getBase64Url),
    )

  def editAttestationObject(
      name: String,
      value: JsonNode,
  ): RegistrationTestData =
    copy(
      attestationObject = new ByteArray(
        JacksonCodecs.cbor.writeValueAsBytes(
          JacksonCodecs.cbor
            .readTree(attestationObject.getBytes)
            .asInstanceOf[ObjectNode]
            .set(name, value)
        )
      )
    )
  def updateAttestationObject(
      name: String,
      updater: JsonNode => JsonNode,
  ): RegistrationTestData = {
    val attObj = JacksonCodecs.cbor.readTree(attestationObject.getBytes)
    copy(
      attestationObject = new ByteArray(
        JacksonCodecs.cbor.writeValueAsBytes(
          attObj
            .asInstanceOf[ObjectNode]
            .set(name, updater(attObj.get(name)))
        )
      )
    )
  }

  def setAttestationStatementFormat(value: String): RegistrationTestData =
    editAttestationObject(
      "fmt",
      RegistrationTestData.jsonFactory.textNode(value),
    )

  def editAuthenticatorData(
      updater: ByteArray => ByteArray
  ): RegistrationTestData = {
    val attObj: ObjectNode = JacksonCodecs.cbor
      .readTree(attestationObject.getBytes)
      .asInstanceOf[ObjectNode]
    val authData: ByteArray = new ByteArray(attObj.get("authData").binaryValue)
    editAttestationObject(
      "authData",
      RegistrationTestData.jsonFactory.binaryNode(updater(authData).getBytes),
    )
  }

  def request: PublicKeyCredentialCreationOptions =
    overrideRequest getOrElse PublicKeyCredentialCreationOptions
      .builder()
      .rp(rpId)
      .user(userId)
      .challenge(clientData.getChallenge)
      .pubKeyCredParams(
        List(
          PublicKeyCredentialParameters.ES256,
          PublicKeyCredentialParameters.EdDSA,
          PublicKeyCredentialParameters.RS256,
        ).asJava
      )
      .extensions(requestedExtensions)
      .authenticatorSelection(authenticatorSelection.asJava)
      .build()

  def response: PublicKeyCredential[
    AuthenticatorAttestationResponse,
    ClientRegistrationExtensionOutputs,
  ] =
    PublicKeyCredential
      .builder()
      .id(
        new AttestationObject(
          attestationObject
        ).getAuthenticatorData.getAttestedCredentialData.get.getCredentialId
      )
      .response(
        AuthenticatorAttestationResponse
          .builder()
          .attestationObject(attestationObject)
          .clientDataJSON(clientDataJsonBytes)
          .build()
      )
      .clientExtensionResults(clientExtensionResults)
      .build()

  def keypair: Option[KeyPair] =
    privateKey map { privateKey =>
      val pubKeyCoseBytes = new AttestationObject(
        attestationObject
      ).getAuthenticatorData.getAttestedCredentialData.get.getCredentialPublicKey
      val pubkey = WebAuthnCodecs.importCosePublicKey(pubKeyCoseBytes)
      val prikey = WebAuthnTestCodecs.importPrivateKey(
        privateKey,
        WebAuthnCodecs.getCoseKeyAlg(pubKeyCoseBytes).get,
      )
      new KeyPair(pubkey, prikey)
    }
}

case class AssertionTestData(
    request: AssertionRequest,
    response: PublicKeyCredential[
      AuthenticatorAssertionResponse,
      ClientAssertionExtensionOutputs,
    ],
) {
  def regenerate(testData: RegistrationTestData): AssertionTestData = {
    copy(
      response = TestAuthenticator.createAssertionFromTestData(
        testData,
        request.getPublicKeyCredentialRequestOptions,
      )
    )
  }
}
